package com.easytouch.core;

import android.os.SystemClock;
import android.util.Pair;

import com.easytouch.core.encryption.Base64;
import com.easytouch.core.utils.FileTools;
import com.easytouch.core.utils.Log;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.Locale;

/**
 * Created by Administrator on 2017/12/6.
 */

public class TYPayLongThread {

    private static TYPayLongThread mTYPayLongThread;

    private static Log mLogger; //日志

    private static boolean isStopped = true;

    private Socket socket = null;
    private InputStream in = null;
    private OutputStream out = null;

    private ReadThread mReadThread = null;
    private WriteThread mWriteThread = null;

    private static LinkedList<String> mQueue = new LinkedList<String>(); // 主动指令队列

    private String mHost = "upns.pec.com.cn";     //新测试地址:nscreentest.pec.com.cn 测试地址:shwt.pec.com.cn   nscreentest.pec.com.cn

    private boolean updateGoodsPriceIsSuccess=false;

    //   正式环境nscreen.pec.com.cn 端口8889
    private TYPayLongThread() {
        mLogger = new Log("TYPayLongThread.txt");
        if (mHost == null || "".equals(mHost)) {
            mHost = "upns.pec.com.cn";
        }
        mWriteThread = new WriteThread();
        mWriteThread.start();
        mReadThread = new ReadThread();
        mReadThread.start();
    }

    public static TYPayLongThread getInstance() {
        if (mTYPayLongThread == null) {
            mTYPayLongThread = new TYPayLongThread();
        }
        return mTYPayLongThread;
    }

    private synchronized static void appendQueueData(String data) {
        mQueue.offer(data);
    }

    private synchronized static String getQueueData() {
        return mQueue.poll();
    }

    private synchronized static int getQueueCount() {
        return mQueue.size();
    }

    public void stopThread() {
        isStopped = true;
    }

    private void connectServer() throws IOException, SocketException, UnknownHostException {
        socket = new Socket();
        socket.setSoTimeout(1000 * 60 * 5);
        InetSocketAddress socAddress = new InetSocketAddress(mHost, 8889);
        socket.connect(socAddress, 30000);
        socket.setKeepAlive(true);
        in = socket.getInputStream();
        out = socket.getOutputStream();
    }

    private boolean isConnectSuccess() {
        try {
            connectServer();
        } catch (UnknownHostException e) {
            socket = null;
            in = null;
            out = null;
            mLogger.e("pay long1 " + e.getMessage());
            return false;
        } catch (SocketException e) {
            socket = null;
            in = null;
            out = null;
            mLogger.e("pay long2 " + e.getMessage());
            return false;
        } catch (IOException e) {
            socket = null;
            in = null;
            out = null;
            mLogger.e("pay long3 " + e.getMessage());
            return false;
        }
        return true;
    }

    private boolean checkConnect() {
        if (socket != null && in != null && out != null) {
            if (socket.isConnected()) {
                return true;
            } else {
                closeConnect();
                return false;
            }
        } else
            return false;
    }

    private boolean retryConnect() {
        return isConnectSuccess();
    }

    private synchronized void closeConnect() {
        try {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
            if (socket != null) {
                socket.close();
            }
        } catch (IOException e1) {
        }
        socket = null;
        in = null;
        out = null;
    }

    private String encryptData(String data) {//加密
        String msg = Base64.encode(data.getBytes());
        char firstData = msg.charAt(0);
        char secondeData = msg.charAt(1);
        char lastThreeData = msg.charAt(msg.length() - 3);
        char lastFourData = msg.charAt(msg.length() - 4);
        data = lastThreeData + "" + lastFourData + msg.substring(2, msg.length() - 4) + secondeData + "" + firstData + msg.substring(msg.length() - 2);
        return data;
    }

    private String decryptData(String data) {//解密
        char firstData = data.charAt(0);
        mLogger.i(" read readCount firstData:" + firstData);
        char secondeData = data.charAt(1);
        mLogger.i(" read readCount secondeData:" + secondeData);
        char lastThreeData = data.charAt(data.length() - 3);
        mLogger.i(" read readCount lastThreeData:" + lastThreeData);
        char lastFourData = data.charAt(data.length() - 4);
        mLogger.i(" read readCount lastFourData:" + lastFourData);
        String dataTwo = lastThreeData + "" + lastFourData + data.substring(2, data.length() - 4) + secondeData + "" + firstData + data.substring(data.length() - 2);
        mLogger.i(" read readCount dataTwo:" + dataTwo);
        byte[] decodeTwo = Base64.decode(dataTwo);
        mLogger.i(" read readCount decodeTwo:" + decodeTwo);
        String newData = new String(decodeTwo);
        mLogger.i(" read readCount newData:" + newData);
        String substring = newData.substring(0, newData.length() - 6);
        mLogger.i(" read readCount substring:" + substring);
        return substring;
    }

    private class ReadThread extends Thread {
        private boolean run = true;

        @Override
        public void run() {
            super.run();

            while (run) {
                SystemClock.sleep(100);
                if (!checkConnect()) {
                    mLogger.i("pay long fail 01");
                    continue;
                }
                try {

                    byte[] buf = new byte[128];
                    int readCount = in.read(buf);

                    mLogger.i(" read readCount:" + readCount);
                    if (readCount == -1) {
                        mLogger.i(" read -1");
                        continue;
                    }
                    String sString = new String(buf);
                    String newString = sString.trim();
                    mLogger.i(" sString:" + sString + ",Time:" + System.currentTimeMillis());
                    mLogger.i(" newString:" + newString + ",Time:" + System.currentTimeMillis());
                    if ("".equals(newString.trim())) {
                        throw new SocketTimeoutException();
                    }
                    //解析,第一步，换位，第二步base64 解密，第三步  解析数据
                    String newData = decryptData(newString);
                    mLogger.i(" read newData:" + newData);
                    if (newData.equals("00")) //签到和心跳的应答回应
                    {
                        mLogger.i("pay long heartbeat ok");
                    } else if (newData.length() == 34) {
                        mLogger.i("handlypay01");
                        // 支付成功处理 出货 1、解析数据，发送出货指令；然后获取到出货状态后 appendQueue("修改订单出货状态指令")
                        String orderId = newData.substring(0, 22);
                        String machinNo = newData.substring(22, 30);
                        String box = newData.substring(30, 32);
                        String column = newData.substring(32, 34);
                        sendOutGoodsResult(orderId, "3");
                        mLogger.i("read orderId:" + orderId + ",machinNo:" + machinNo + ",box:" + box + ",column:" + column);
                        outGoods(orderId, box, column, 100 + "", DriverThread.OUT_GOODS_ALIPAY);
                    } else if (newData.length() == 23) {
                        String state = newData.substring(newData.length() - 1);
                        mLogger.i("modity order outgoods state:" + state);
                    }else if (newData.length() == 18) {
                        //拿到 商品id 调用修改价格的方法
                        mLogger.e("newData 18:"+newData.length());
                        String machNo = newData.substring(0, 8);
                        String boxNo = newData.substring(8, 10);
                        String roadNo = newData.substring(10, 12);
                        String price = newData.substring(12);

//                        String goodsInfo = DriverThread.getInstance().getGoodsInfo(Integer.parseInt(boxNo), Integer.parseInt(roadNo));
//                        mLogger.e("newData goodsInfo:"+goodsInfo);
//                        JSONObject obj=new JSONObject(goodsInfo);
//                        String code = obj.getString("code");


                        //修改主控商品价格
//                        boolean isUpdateSuccess= updateMachineGoodsPrice(Integer.parseInt(boxNo), Integer.parseInt(roadNo), Integer.parseInt(price), Integer.parseInt(roadNo));

                        MyThread myThread = new MyThread(Integer.parseInt(boxNo),Integer.parseInt(roadNo),Integer.parseInt(price),Integer.parseInt(roadNo));
                        myThread.start();

                        mLogger.e("updateGoodsPriceIsSuccess:"+updateGoodsPriceIsSuccess);
                        if(updateGoodsPriceIsSuccess){
                            String newSendData = "02" + machNo + boxNo + roadNo + price + "shtyzx";
                            mLogger.e("newSendData:"+newSendData);
                            String s = encryptData(newSendData);
                            mLogger.e("newSendData s:"+s);
                            appendQueueData(s);
                        }
                    }else if(newData.length() == 1){
                        mLogger.e("修改价格数据是否成功："+ ("1" .equals(newData)  ?"成功":"失败"));
                    }
                } catch (SocketTimeoutException e) {
                    closeConnect();
                    mLogger.e("pay long timeout");
                } catch (IOException e) {
                    closeConnect();
                    mLogger.e("pay long IO error " + e.getMessage());
                } catch (Exception e) {
                    closeConnect();
                    mLogger.e("pay long data error cause:" + e.getCause()+",msg:"+e.getMessage());
                }
            }
        }


        private boolean updateMachineGoodsPrice(int pBox,int pColumn,int pPrice,int pCode ){
            byte[] bytes = null;
            try {
                bytes = DriverThread.makePriceAndCodeByteArray(pBox, pColumn, pPrice / 10, pCode, false);
                mLogger.e("pay long data bytes " + bytes);
            } catch (NumberFormatException e) {
                mLogger.e("NumberFormatException e " + e.getMessage());
               return updateGoodsPriceIsSuccess=false;
            }
            if (bytes != null) {
                DriverThread.getInstance().appendQueueData(bytes);
                boolean isSuccess = false;
                int times = 5;
                while (times > 0) {
                    SystemClock.sleep(1000);
                    times--;
                    if (DriverThread.getInstance().cmdResult == DriverThread.CMD_ACK) {
                        isSuccess = true;
                        break;
                    }
                }
                if (isSuccess) {
                    mLogger.e("updateGoodsPriceIsSuccess " + updateGoodsPriceIsSuccess);
                   return updateGoodsPriceIsSuccess=true;
                }
            }
            return false;
        }


        class MyThread extends Thread {
            private int pBox;
            private int pColumn;
            private int pPrice;
            private int pCode;
            private MyThread(int box,int column,int price,int code){
                this.pBox=box;
                this.pColumn=column;
                this.pPrice=price;
                this.pCode=code;

            }
            @Override
            public void run() {
                super.run();
                //修改商品ID和价格
                byte[] bytes = null;
                try {
                    bytes = DriverThread.makePriceAndCodeByteArray(pBox, pColumn, pPrice / 10, pCode, false);
                } catch (NumberFormatException e) {
                    updateGoodsPriceIsSuccess=false;
                }
                if (bytes != null) {
                    DriverThread.getInstance().appendQueueData(bytes);
                    boolean isSuccess = false;
                    int times = 5;
                    while (times > 0) {
                        SystemClock.sleep(1000);
                        times--;
                        if (DriverThread.getInstance().cmdResult == DriverThread.CMD_ACK) {
                            isSuccess = true;
                            break;
                        }
                    }
                    if (isSuccess) {
                        updateGoodsPriceIsSuccess=true;
                    }
                }
            }
        }

        /**
         * 处理支付成功请求
         *
         * @param in 输入流
         * @throws IOException IO异常
         */
        private void handlePay(InputStream in) throws IOException {
            //先读取长度
            byte[] buf = new byte[2];
            int r = in.read(buf);
            if (r == -1) {
                throw new IOException("pay long read 12 error");
            }
            String sString = new String(buf);
            mLogger.i("pay long 12 length:" + sString);
            if ("".equals(sString.trim())) {
                throw new SocketTimeoutException();
            }
            int len = 0;
            try {
                len = Integer.parseInt(sString);
            } catch (NumberFormatException e) {
                throw new IOException("pay long read 12 number format");
            }
            //获取数据
            buf = new byte[len];
            r = in.read(buf);
            int read = r;
            while (read < len) {
                if (r == -1) {
                    throw new IOException("pay long read 12 error");
                } else {
                    r = in.read(buf, read, len - read);
                    read += r;
                }
            }
            sString = new String(buf);
            mLogger.i("pay long 12 data:" + sString);
            //验签
            String newString = sString.trim();
            mLogger.i(" sString:" + sString + ",Time:" + System.currentTimeMillis());
            mLogger.i(" newString:" + newString + ",Time:" + System.currentTimeMillis());
            if ("".equals(newString.trim())) {
                throw new SocketTimeoutException();
            }
            //解析,第一步，换位，第二步base64 解密，第三步  解析数据
            String newData = decryptData(newString);
            if (newData.equals("00")) //签到和心跳的应答回应
            {
                mLogger.i("pay long heartbeat ok");
            } else if (newData.length() == 34) {
                String orderId = newData.substring(0, 22);
                String machinNo = newData.substring(22, 30);
                String box = newData.substring(30, 32);
                String column = newData.substring(32, 34);
                sendOutGoodsResult(orderId, "3");
                mLogger.i("read orderId:" + orderId + ",machinNo:" + machinNo + ",box:" + box + ",column:" + column);
                outGoods(orderId, box, column, 100 + "", DriverThread.OUT_GOODS_ALIPAY);
            } else if (newData.length() == 23) {
                mLogger.i("handlypay02");
                String state = newData.substring(newData.length() - 1);
                mLogger.i("modity order outgoods state:" + state);
            }
        }

        private void outGoods(final String orderId, final String box, final String column, final String price, final String type) {
            int b, c, p;
            try {
                b = Integer.parseInt(box);
                c = Integer.parseInt(column);
                p = Integer.parseInt(price);
            } catch (NumberFormatException e) {
                mLogger.e("pay long outGoods number format error:" + e.toString());
                //发送出货失败指令
                sendOutGoodsResult(orderId, "3");
                return;
            }
            String outGoodsType = DriverThread.OUT_GOODS_WEIXINPAY;
            if (type.equals("1")) {
                outGoodsType = DriverThread.OUT_GOODS_WEIXINPAY;
            } else if (type.equals("2")) {
                outGoodsType = DriverThread.OUT_GOODS_BAIPAY;
            } else if (type.equals("3")) {
                outGoodsType = DriverThread.OUT_GOODS_ALIPAY;
            } else if (type.equals("7")) {
                outGoodsType = DriverThread.OUT_GOODS_CCB;
            } else if (type.equals("0")) {
                //充电请求
//                requestCharge(orderId);
                return;
            }
            SimpleDateFormat sd = new SimpleDateFormat("HHmmss", Locale.US);
            String tradeTrace = sd.format(new Date());
            boolean result = DriverThread.getInstance().outGoods(b, c, p, outGoodsType, tradeTrace, orderId);
            if (!result) {
                mLogger.e("pay long outGoods result false");
                //发送出货失败指令
                sendOutGoodsResult(orderId, "2");
                return;
            }
            //DriverThread.getInstance().addOrderId(tradeTrace, orderId);
            int step = 0;
            int r = -1;
            try {
                while (step <= 120) {
                    Thread.sleep(500);
                    step++;
                    Pair<Integer, Integer> pair = DriverThread.getInstance().getResult(tradeTrace);
                    if (pair != null) {
                        r = pair.first;
                        break;
                    }
                }
            } catch (InterruptedException e) {
            }
            mLogger.i("outGoods result:" + String.valueOf(r));
            if (r == 0) { // 出货成功
                //发送出货成功指令
                sendOutGoodsResult(orderId, "1");
            } else { // 出货失败
                //发送出货失败指令
                sendOutGoodsResult(orderId, "2");
            }
        }

        private void sendOutGoodsResult(final String orderId, String num) {

            String data = "";
            if (num.equals("1")) {
                data = "2";
            } else if (num.equals("2")) {
                data = "3";
            } else if (num.equals("3")) {
                data = "1";
            }
            String outGoodsData = orderId + data + "shtyzx";
            String newOutGoodsData = encryptData(outGoodsData);
            mLogger.i("outGoodsData:" + outGoodsData + ",newOutGoodsData:" + newOutGoodsData);
            appendQueueData(newOutGoodsData);
        }


        public void cancelThread() {
            run = false;
            this.interrupt();
        }

        public boolean isRunning() {
            return run;
        }
    }

    private class WriteThread extends Thread {
        private boolean run = true;

        private static final long HEARTBEAT_TIME = 1000 * 10;
        private long heartbeatLastTime = 0;

        @Override
        public void run() {
            super.run();

            while (run) {
                SystemClock.sleep(100);
                if (!checkConnect()) {
                    if (!retryConnect()) {
                        mLogger.e("pay long retry connect failed");
                        continue;
                    }
                }
                //先检查是否队列中有要发送的数据
                if (getQueueCount() > 0) {
                    if (!checkConnect()) {
                        if (!retryConnect()) {
                            mLogger.e("pay long retry connect failed");
                        } else {
                            String queueStr = getQueueData();
                            if (!doSendQueueData(queueStr)) {
                                mLogger.e("pay long queue failed");
                            }
                        }
                    } else {
                        String queueStr = getQueueData();
                        mLogger.e("queueStr:" + queueStr);
                        if (!doSendQueueData(queueStr)) {
                            mLogger.e("pay long queue failed");
                        }
                    }
                } else {
                    //发送心跳
                    if (!checkConnect()) {
                        if (!retryConnect()) {
                            mLogger.e("pay long retry connect failed");
                        } else {
                            if (!doSendHeartBeatData()) {
                                mLogger.e("pay long heartbeat failed");
                            }
                        }
                    } else {
                        if (!doSendHeartBeatData()) {
                            mLogger.e("pay long heartbeat failed");
                        }
                    }
                }

            }
        }

        private boolean doSendQueueData(String queueStr) {
            int retry = 3;
            boolean isSuccess = false;
            while (retry > 0) {
                try {
                    //发送数据
                    mLogger.i("pay long send:" + queueStr);
                    out.write(queueStr.getBytes());
                    out.flush();
                    isSuccess = true;
                    heartbeatLastTime = System.currentTimeMillis();
                } catch (SocketTimeoutException e) {
                    mLogger.e("pay long send queue timeout");
                } catch (IOException e) {
                    mLogger.e("pay long send queue IO error:" + e.getMessage());
                    break;
                } catch (Exception e) {
                    closeConnect();
                    mLogger.e("pay long send queue data error:" + e.getMessage());
                    break;
                }
                if (isSuccess) {
                    break;
                }
                retry--;
            }
            if (isSuccess) {
                SystemClock.sleep(100);
                return true;
            } else {
                closeConnect();
                return false;
            }
        }

        private boolean doSendHeartBeatData() {
            long currentTime = System.currentTimeMillis();
            if (currentTime - heartbeatLastTime < HEARTBEAT_TIME) {
                return true;
            }
            heartbeatLastTime = currentTime;
            int retry = 3;
            boolean isSuccess = false;
            while (retry > 0) {
                try {
                    //心跳通讯协议
                    //请求：01+8位机器号
                    //应答：00
                    String sign = "01" + Configure.getMacNo() + "shtyzx";
//                    FileTools.getMacFromFile();
                    mLogger.i("sign:" + sign);
                    String newData = encryptData(sign);
                    mLogger.i("pay long send heartbeat:" + newData + ",machNo:" + Configure.getMacNo());
                    out.write(newData.getBytes());
                    out.flush();
                    isSuccess = true;
                } catch (SocketTimeoutException e) {
                    mLogger.e("pay long send heartbeat timeout");
                } catch (IOException e) {
                    mLogger.e("pay long send heartbeat IO error:" + e.getMessage());
                    break;
                } catch (Exception e) {
                    closeConnect();
                    mLogger.e("pay long send heartbeat data error:" + e.getMessage());
                    break;
                }
                if (isSuccess) {
                    break;
                }
                retry--;
            }
            if (isSuccess) {
                SystemClock.sleep(100);
                return true;
            } else {
                closeConnect();
                return false;
            }
        }

        public void cancelThread() {
            run = false;
            this.interrupt();
        }

        public boolean isRunning() {
            return run;
        }
    }

}
